//----------------------------------------------------------------------------
// progcmd.cpp
//
// progress dialog for swine
//
// Copyright (C) 2011 Neil Butterworth
//----------------------------------------------------------------------------

#include <windows.h>
#include <commctrl.h>
#include <string>
#include <iostream>
#include "command.h"
#include "cmdline.h"
#include "util.h"
#include "resource.h"
#include "error.h"

using namespace std;

namespace Swine {

//----------------------------------------------------------------------------
// Command & option names
//----------------------------------------------------------------------------

const char * const TEE_CMD 		= "tee";
const char * const PROG_CMD 	= "prog";
const char * const CAPTION_OPT 	= "caption";
const char * const SIZE_OPT 	= "size";

//----------------------------------------------------------------------------
// Help
//----------------------------------------------------------------------------

const char * const TEE_HELP =
	 "display data as it is piped through\n"
	"options:\n"
	" --caption     specify message box caption (default is 'Tee') \n";

const char * const PROG_HELP =
	 "display progress bar dialog\n"
	"options:\n"
	" --caption     specify message box caption (default is 'Progress') \n"
	" --size        logical size of progress bar (default is 100 ) \n";

//----------------------------------------------------------------------------
// Command class and registration
//----------------------------------------------------------------------------

class TeeCmd : public Command {

	public:

		TeeCmd() : Command( TEE_CMD, TEE_HELP ) {}

		int Execute( CmdLine & cl ) const;

};

class ProgCmd : public Command {

	public:

		ProgCmd() : Command( PROG_CMD, PROG_HELP ) {}

		int Execute( CmdLine & cl ) const;

};

static AddCommand <TeeCmd> cmd1_;
static AddCommand <ProgCmd> cmd2_;


//----------------------------------------------------------------------------
// Indicator if we are still processing Windows messages
//----------------------------------------------------------------------------

static bool okmsg = false;

//----------------------------------------------------------------------------
// Trivial dialog proc for tee & prog command
//----------------------------------------------------------------------------

static BOOL CALLBACK TeeProgDialogProc( HWND hwnd, UINT message, WPARAM , LPARAM  ) {

    switch (message)    {
		case WM_COMMAND:
			return TRUE;

		case WM_INITDIALOG:
			return TRUE;

		case WM_DESTROY:
			okmsg = false;
			PostQuitMessage(0);
			return TRUE;

		case WM_CLOSE:
			DestroyWindow (hwnd);
			return TRUE;
	}

    return FALSE;
}

//----------------------------------------------------------------------------
// Open dialog box, setting caption and size of progress bar. Then step
// the progress bar for every line of input read
//----------------------------------------------------------------------------

int ProgCmd :: Execute( CmdLine & cl ) const {
	string caption = cl.ExtractOption( CAPTION_OPT, "Tee" );
	string sz = cl.ExtractOption( SIZE_OPT, "10" );
	cl.MustBeEmpty();

	int size = atoi( sz.c_str() );
	if ( size <= 0 ) {
		throw Error( "Invalid progress bar ssize: " + sz );
	}
	HWND dlg = CreateDialog(  GetModuleHandle(0),
								MAKEINTRESOURCE( IDD_PROGDLG  ),
								 0, & TeeProgDialogProc );
	SetWindowText( dlg, caption.c_str() );
	SendMessage( MustGetControl( dlg, IDC_PROGBAR), PBM_SETRANGE,
									0, MAKELPARAM( 0, size ) );
	bool okinput = true;
	okmsg = true;
	string line;

    while ( okinput && okmsg ) {
		if ( okmsg ) {
			MSG  msg;
			if ( PeekMessage( & msg, 0, 0, 0, PM_NOREMOVE ) ) {
				if ( GetMessage( & msg, 0, 0, 0 ) ) {
					if ( ! IsDialogMessage( dlg, & msg ) ) {
						TranslateMessage( & msg );
						DispatchMessage( & msg );
					}
				}
				else {
					okmsg = false;
				}
			}
		}
		if ( std::getline( cin, line ) ) {
			std::cout << line << "\n";
			if ( okmsg  ) {
				SendMessage( MustGetControl( dlg, IDC_PROGBAR ), PBM_STEPIT, 0, 0 );
			}
		}
		else {
			okinput = false;
		}
	}
 	return 0;
}



//----------------------------------------------------------------------------
// Custom excecute which creates the dialog and then processes their messages
// while also reading standard input and wtiting to standard output.
//----------------------------------------------------------------------------

int TeeCmd :: Execute( CmdLine & cl ) const {

	string caption = cl.ExtractOption( CAPTION_OPT, "Tee" );
	cl.MustBeEmpty();

	HWND dlg = CreateDialog(  GetModuleHandle(0),
								MAKEINTRESOURCE( IDD_TEEDLG  ),
								 0, & TeeProgDialogProc );
	SetWindowText( dlg, caption.c_str() );
	bool okinput = true;
	okmsg = true;
	string line;

    while ( okinput && okmsg ) {
		if ( okmsg ) {
			MSG  msg;
			if ( PeekMessage( & msg, 0, 0, 0, PM_NOREMOVE ) ) {
				if ( GetMessage( & msg, 0, 0, 0 ) ) {
					if ( ! IsDialogMessage( dlg, & msg ) ) {
						TranslateMessage( & msg );
						DispatchMessage( & msg );
					}
				}
				else {
					okmsg = false;
				}
			}
		}
		if ( std::getline( cin, line ) ) {
			std::cout << line << "\n";
			if ( okmsg  ) {
				SetWindowText( MustGetControl( dlg, IDC_PROGED ), line.c_str() );
			}
		}
		else {
			okinput = false;
		}
	}
 	return 0;
}




} // namespace
